import { http } from "@kit.NetworkKit";
import { AuthInfo } from "../beans/Infos";
import { JSONObject } from "../beans/JSONObject";
import { JSON, util } from "@kit.ArkTS";
import { cloudDatabase } from "../cloudDatabase"
import AuthManager from "./AuthManager";

export default class QueryManager {
  private static readonly TYPE_MAP: {[key: number]: string} = {
    1: "bl", // 1：TYPE_BOOLEAN，布尔类型。
    2: "b", // 2：TYPE_BYTE，byte类型。
    3: "st", // 3：TYPE_SHORT，short类型。
    4: "i", // 4：TYPE_INT32，int类型。
    5: "l", // 5：TYPE_LONG，long类型。
    6: "f", // 6：TYPE_FLOAT，float类型。
    7: "d", // 7：TYPE_DOUBLE，double类型。
    8: "ba", // 8：TYPE_BYTE_ARRAY，byte数组类型。
    9: "s", // 9：TYPE_STRING，String类型。
    10: "s", // 10：TYPE_DATE，date类型。
    11: "s", // 11：TYPE_TEXT，文本类型。
    12: "i", // 12：TYPE_AUTO_INCREMENT_INT，int自增类型。
    13: "l" // 13：TYPE_AUTO_INCREMENT_LONG，long自增类型。
  }

  private static instance: QueryManager;

  // 私有构造函数，防止外部通过 new 创建实例
  private constructor() {}

  // 静态方法，用于获取单例实例
  public static getInstance(): QueryManager {
    if (!QueryManager.instance) {
      QueryManager.instance = new QueryManager();
    }
    return QueryManager.instance;
  }

  static async query<T extends cloudDatabase.DatabaseObject>(storeName: string, condition: cloudDatabase.DatabaseQuery<T>, schemaVersion: number, queryType?: cloudDatabase.QueryCalculate): Promise<Array<T> | number> {
    // 每一个httpRequest对应一个HTTP请求任务，不可复用
    let httpRequest = http.createHttp();
    const url = "https://connect-drcn.dbankcloud.cn/agc/apigw/clouddb/clouddbservice/sync/query?_v=4"
    let finalQueryType: number = 0
    if (queryType !== undefined) {
      finalQueryType = queryType + 1
    }
    let conditionJson = JSON.stringify(condition._queryConditions)
    conditionJson = conditionJson.replaceAll("\"", "\\\"")
    const jsonStr = "{\n" +
      "  \"msgInfo\": {\n" +
      "    \"type\": 5,\n" +
      "    \"opStore\": {\n" +
      `      \"storeName\": \"${storeName}\"\n` +
      "    }\n" +
      "  },\n" +
      "  \"clientInfo\": {\n" +
      `    "appVer": ${schemaVersion}\n` +
      "  },\n" +
      "  \"queryReqMsg\": {\n" +
      `    \"queryType\" : ${finalQueryType},\n` +
      `    "queryTable" : "${new condition.entityClass().naturalbase_ClassName()}",\n` +
      `    "queryCond" : "{\\\"queryConditions\\\":${conditionJson}}\"\n` +
      "  }\n" +
      "}"
    let data: http.HttpResponse
    try {
      data = await httpRequest.request(
        // 填写HTTP请求的URL地址，可以带参数也可以不带参数。URL地址需要开发者自定义。请求的参数可以在extraData中指定
        url,
        {
          method: http.RequestMethod.POST,
          extraData: jsonStr,
          header: {
            'Content-Type': 'application/json',
            "Authorization": "Bearer " + AuthManager.token,
            "client_id": AuthInfo.clientID,
            "access_token": AuthManager.accessToken,
            "productId": AuthInfo.productID
          },

        })
    } catch (err) {
      console.error('error:' + JSON.stringify(err));
      return Promise.reject()
    }
    const arrayBuffer = data!.result as ArrayBuffer

    const decoder = util.TextDecoder.create("utf-8")
    const uint8Array = new Uint8Array(arrayBuffer)
    const response = decoder.decodeToString(uint8Array)

    const rawJson: JSONObject = JSON.parse(response) as JSONObject

    // 聚合查询
    if (queryType !== undefined) {
      const queryResMsg = rawJson.queryResMsg as JSONObject
      const aggQueryRes = queryResMsg.aggQueryRes as JSONObject

      let doubleRes = aggQueryRes.doubleRes as string
      if (doubleRes !== undefined) {
        return Promise.resolve(Number(doubleRes))
      }
      const longRes = aggQueryRes.longRes as string

      return Promise.resolve(Number(longRes))
    }

    // 字段数组
    const schemas = rawJson.schemas as JSONObject[]
    const fs = schemas[0].fs as JSONObject[]
    // 数据数组
    const opData = rawJson.opData as JSONObject[]
    const os = opData[0].os as JSONObject[]
    // 解析
    const result: T[] = this.deserialization(condition.entityClass, fs, os)
    httpRequest.destroy()

    return Promise.resolve(result)
  }

  private static deserialization<T extends cloudDatabase.DatabaseObject>(entityClass: new () => T, schemas: JSONObject[], opData: JSONObject[]): T[] {
    const result: T[] = []
    opData.forEach((value: JSONObject) => {
      const instance = new entityClass()
      schemas.forEach((schema: JSONObject, index: number) => {
        const fsSchema = schema.n as string
        const fs = value.fs as JSONObject[]
        const dataTypeStr = this.TYPE_MAP[schema.t as number]
        const fsOpData = fs[index][dataTypeStr]
        instance[fsSchema] = fsOpData
      })
      result.push(instance)
    })
    return result
  }
}